#include <fstream>
#include <random>
#include <thread>

#include <bthread/bthread.h>
#include <glog/logging.h>
#include <gtest/gtest.h>

#include "hawking/util/node_content.pb.h"
#include "doc/document_creator.h"
#include "index/attribute_index/attribute_mem_indexer/single_value_attribute_mem_indexer.h"
#include "index/attribute_index/attribute_mem_indexer/multi_value_attribute_mem_indexer.h"
#include "util/file_wrapper/file_wrapper.h"

using namespace hawking::indexlib;
DEFINE_int32(attr_test_tasks, 128, "num of threads or bthreads");
std::uniform_int_distribution<int> dis(0, 10000000);
std::uniform_int_distribution<int> dis2(0, 100);
std::default_random_engine e{std::random_device{}()};

void* Write(void* arg) {
    SingleValueAttributeMemIndexer<int64_t>* single_attr_mem_indexer =
        reinterpret_cast<SingleValueAttributeMemIndexer<int64_t>*>(arg);
    uint32_t idx = 0;
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    SingleValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64);

    while (1) {
        hawking::util::FieldValue value;
        value.set_int_value(dis(e));
        std::string_view sv = convertor.Encode(&value, single_attr_mem_indexer->GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(idx++);
        single_attr_mem_indexer->AddDocument(doc.get());
        bthread_usleep(1 * 1000);
    }
}

void* Read(void* arg) {
    SingleValueAttributeMemIndexer<int64_t>* single_attr_mem_indexer =
        reinterpret_cast<SingleValueAttributeMemIndexer<int64_t>*>(arg);
    while (1) {
        uint64_t doc_count = single_attr_mem_indexer->DocCount();
        for (uint32_t idx = 0; idx < doc_count; ++idx) {
            hawking::util::FieldValue field_value;
            EXPECT_EQ(true, single_attr_mem_indexer->Read(idx, &field_value));
            // EXPECT_NE(nullptr, data);
            // LOG(INFO) << "read doc " << idx << ", data " << *data;
            bthread_usleep(1 * 1000);
        }
    }
}

bool FunctionTest(SingleValueAttributeMemIndexer<int64_t>& single_attr_mem_indexer) {
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    doc->SetDocId(0);
    SingleValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64);

    hawking::util::FieldValue value;
    value.set_int_value(dis(e));
    std::string_view sv = convertor.Encode(&value, single_attr_mem_indexer.GetPool());
    attr_doc->SetField(0, sv);
    single_attr_mem_indexer.AddDocument(doc.get());

    hawking::util::FieldValue field_value;
    single_attr_mem_indexer.Read(0, &field_value);
    return field_value.int_value() == value.int_value();
}

TEST(single_attribute_test, read_and_write) {
    SingleValueAttributeMemIndexer<int64_t> single_attr_mem_indexer;
    single_attr_mem_indexer.Init(hawking::util::COLUMN_INT64, 0);

    if (!FunctionTest(single_attr_mem_indexer)) {
        return;
    }

    // write bthread
    bthread_t write_bid;
    bthread_start_background(&write_bid, nullptr, Write, &single_attr_mem_indexer);

    // read bhtreads
    std::vector<bthread_t> read_bids;
    read_bids.reserve(FLAGS_attr_test_tasks);
    for (size_t idx = 0; idx < FLAGS_attr_test_tasks; ++idx) {
        read_bids.emplace_back();
        bthread_start_background(&read_bids.back(), nullptr, Read, &single_attr_mem_indexer);
    }

    std::thread stat_thread([&single_attr_mem_indexer](){
        uint64_t idx = 0;
        while (1) {
            LOG(INFO) << "idx " << idx++ << ", doc count " << single_attr_mem_indexer.DocCount();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });
    bthread_join(write_bid, nullptr);
    for (auto read_bid : read_bids) {
        bthread_join(read_bid, nullptr);
    }
    stat_thread.join();
}

void* WriteString(void* arg) {
    MultiValueAttributeMemIndexer<char>* string_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<char>*>(arg);
    uint32_t idx = 0;
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    StringAttributeConvertor convertor(hawking::util::COLUMN_STRING);

    while (1) {
        hawking::util::FieldValue value;
        value.set_bytes_value(std::to_string(dis(e)));
        std::string_view sv = convertor.Encode(&value, string_attr_mem_indexer->GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(idx++);
        string_attr_mem_indexer->AddDocument(doc.get());
        bthread_usleep(1 * 1000);
    }
}

void* ReadString(void* arg) {
    MultiValueAttributeMemIndexer<char>* string_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<char>*>(arg);
    while (1) {
        uint64_t doc_count = string_attr_mem_indexer->DocCount();
        for (uint32_t idx = 0; idx < doc_count; ++idx) {
            hawking::util::FieldValue field_value;
            EXPECT_EQ(true, string_attr_mem_indexer->Read(idx, &field_value));
            // LOG(INFO) << "read doc " << idx << ", data " << *data;
            bthread_usleep(1 * 1000);
        }
    }
}

bool FunctionTest(MultiValueAttributeMemIndexer<char>& string_attr_mem_indexer) {
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    doc->SetDocId(0);
    StringAttributeConvertor convertor(hawking::util::COLUMN_STRING);

    hawking::util::FieldValue value;
    value.set_bytes_value("hello world");
    std::string_view sv = convertor.Encode(&value, string_attr_mem_indexer.GetPool());

    attr_doc->SetField(0, sv);
    string_attr_mem_indexer.AddDocument(doc.get());

    hawking::util::FieldValue field_value;
    string_attr_mem_indexer.Read(0, &field_value);
    return field_value.bytes_value() == "hello world";
}

TEST(string_attribute_test, read_and_write) {
    MultiValueAttributeMemIndexer<char> string_attr_mem_indexer;
    string_attr_mem_indexer.Init(hawking::util::COLUMN_STRING, 0);

    if (!FunctionTest(string_attr_mem_indexer)) {
        return;
    }

    // write bthread
    bthread_t write_bid;
    bthread_start_background(&write_bid, nullptr, WriteString, &string_attr_mem_indexer);

    // read bhtreads
    std::vector<bthread_t> read_bids;
    read_bids.reserve(FLAGS_attr_test_tasks);
    for (size_t idx = 0; idx < FLAGS_attr_test_tasks; ++idx) {
        read_bids.emplace_back();
        bthread_start_background(&read_bids.back(), nullptr, ReadString, &string_attr_mem_indexer);
    }

    std::thread stat_thread([&string_attr_mem_indexer](){
        uint64_t idx = 0;
        while (1) {
            LOG(INFO) << "idx " << idx++ << ", doc count " << string_attr_mem_indexer.DocCount();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });
    bthread_join(write_bid, nullptr);
    for (auto read_bid : read_bids) {
        bthread_join(read_bid, nullptr);
    }
    stat_thread.join();
}

void* WriteMulti(void* arg) {
    MultiValueAttributeMemIndexer<int64_t>* multi_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<int64_t>*>(arg);
    uint32_t idx = 0;
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    MultiValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64_LIST);

    while (1) {
        hawking::util::FieldValue int64_list;
        int32_t r_count = dis2(e);
        for (int32_t idx = 0; idx < r_count; ++idx) {
            int64_list.mutable_int_values()->add_values(dis(e));
        }
        std::string_view sv = convertor.Encode(&int64_list, multi_attr_mem_indexer->GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(idx++);
        multi_attr_mem_indexer->AddDocument(doc.get());
        bthread_usleep(1 * 1000);
    }
}

void* ReadMulti(void* arg) {
    MultiValueAttributeMemIndexer<int64_t>* multi_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<int64_t>*>(arg);
    while (1) {
        uint64_t doc_count = multi_attr_mem_indexer->DocCount();
        for (uint32_t idx = 0; idx < doc_count; ++idx) {
            hawking::util::FieldValue v_int64_list;
            multi_attr_mem_indexer->Read(idx, &v_int64_list);
            // LOG(INFO) << "read doc " << idx << ", data " << *data;
            bthread_usleep(1 * 1000);
        }
    }
}

template<class T>
bool FunctionTest(MultiValueAttributeMemIndexer<T>& multi_value_attr_mem_indexer) {
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    doc->SetDocId(0);

    MultiValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64_LIST);
    hawking::util::FieldValue int64_list;
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    int64_list.mutable_int_values()->add_values(dis(e));
    std::string_view sv = convertor.Encode(&int64_list, multi_value_attr_mem_indexer.GetPool());

    attr_doc->SetField(0, sv);
    multi_value_attr_mem_indexer.AddDocument(doc.get());

    hawking::util::FieldValue v_int64_list;
    multi_value_attr_mem_indexer.Read(0, &v_int64_list);
    EXPECT_EQ(true, int64_list.int_values().values().size() == v_int64_list.int_values().values().size());
    if (int64_list.int_values().values().size() != v_int64_list.int_values().values().size()) {
        return false;
    }
    for (int32_t idx = 0; idx < int64_list.int_values().values_size(); ++idx) {
        EXPECT_EQ(true, int64_list.int_values().values(idx) == v_int64_list.int_values().values(idx));
        if (int64_list.int_values().values(idx) != v_int64_list.int_values().values(idx)) {
            return false;
        }
    }

    return true;
}

TEST(multi_value_attribute_test, read_and_write) {
    MultiValueAttributeMemIndexer<int64_t> multi_value_attr_mem_indexer;
    multi_value_attr_mem_indexer.Init(hawking::util::COLUMN_INT64_LIST, 0);

    if (!FunctionTest(multi_value_attr_mem_indexer)) {
        return;
    }

    // write bthread
    bthread_t write_bid;
    bthread_start_background(&write_bid, nullptr, WriteMulti, &multi_value_attr_mem_indexer);

    // read bhtreads
    std::vector<bthread_t> read_bids;
    read_bids.reserve(FLAGS_attr_test_tasks);
    for (size_t idx = 0; idx < FLAGS_attr_test_tasks; ++idx) {
        read_bids.emplace_back();
        bthread_start_background(&read_bids.back(), nullptr, ReadMulti, &multi_value_attr_mem_indexer);
    }

    std::thread stat_thread([&multi_value_attr_mem_indexer](){
        uint64_t idx = 0;
        while (1) {
            LOG(INFO) << "idx " << idx++ << ", doc count " << multi_value_attr_mem_indexer.DocCount();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });
    bthread_join(write_bid, nullptr);
    for (auto read_bid : read_bids) {
        bthread_join(read_bid, nullptr);
    }
    stat_thread.join();
}

template<>
bool FunctionTest(MultiValueAttributeMemIndexer<std::string>& multi_string_attr_mem_indexer) {
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    doc->SetDocId(0);

    MultiStringAttributeConvertor convertor(hawking::util::COLUMN_STRING_LIST);
    hawking::util::FieldValue bytes_list;
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
    std::string_view sv = convertor.Encode(&bytes_list, multi_string_attr_mem_indexer.GetPool());

    attr_doc->SetField(0, sv);
    multi_string_attr_mem_indexer.AddDocument(doc.get());

    hawking::util::FieldValue v_bytes_list;
    multi_string_attr_mem_indexer.Read(0, &v_bytes_list);
    EXPECT_EQ(true, bytes_list.bytes_values().values().size() == v_bytes_list.bytes_values().values().size());
    if (bytes_list.bytes_values().values().size() != v_bytes_list.bytes_values().values().size()) {
        return false;
    }
    for (int32_t idx = 0; idx < bytes_list.bytes_values().values_size(); ++idx) {
        EXPECT_EQ(true, bytes_list.bytes_values().values(idx) == v_bytes_list.bytes_values().values(idx));
        if (bytes_list.bytes_values().values(idx) != v_bytes_list.bytes_values().values(idx)) {
            return false;
        }
    }

    return true;
}

void* WriteMultiString(void* arg) {
    MultiValueAttributeMemIndexer<std::string>* multi_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<std::string>*>(arg);
    uint32_t idx = 0;
    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    MultiStringAttributeConvertor convertor(hawking::util::COLUMN_STRING_LIST);

    while (1) {
        hawking::util::FieldValue bytes_list;
        int32_t r_count = dis2(e);
        for (int32_t idx = 0; idx < r_count; ++idx) {
            bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
        }

        std::string_view sv = convertor.Encode(&bytes_list, multi_attr_mem_indexer->GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(idx++);
        multi_attr_mem_indexer->AddDocument(doc.get());
        bthread_usleep(1 * 1000);
    }
}

void* ReadMultiString(void* arg) {
    MultiValueAttributeMemIndexer<std::string>* multi_attr_mem_indexer =
        reinterpret_cast<MultiValueAttributeMemIndexer<std::string>*>(arg);
    while (1) {
        uint64_t doc_count = multi_attr_mem_indexer->DocCount();
        for (uint32_t idx = 0; idx < doc_count; ++idx) {
            hawking::util::FieldValue bytes_list;
            multi_attr_mem_indexer->Read(idx, &bytes_list);
            // LOG(INFO) << "read doc " << idx << ", data " << *data;
            bthread_usleep(1 * 1000);
        }
    }
}

TEST(multi_string_attribute_test, read_and_write) {
    MultiValueAttributeMemIndexer<std::string> multi_string_attr_mem_indexer;
    multi_string_attr_mem_indexer.Init(hawking::util::COLUMN_STRING_LIST, 0);

    if (!FunctionTest(multi_string_attr_mem_indexer)) {
        return;
    }

    // write bthread
    bthread_t write_bid;
    bthread_start_background(&write_bid, nullptr, WriteMultiString, &multi_string_attr_mem_indexer);

    // read bhtreads
    std::vector<bthread_t> read_bids;
    read_bids.reserve(FLAGS_attr_test_tasks);
    for (size_t idx = 0; idx < FLAGS_attr_test_tasks; ++idx) {
        read_bids.emplace_back();
        bthread_start_background(&read_bids.back(), nullptr, ReadMultiString, &multi_string_attr_mem_indexer);
    }

    std::thread stat_thread([&multi_string_attr_mem_indexer](){
        uint64_t idx = 0;
        while (1) {
            LOG(INFO) << "idx " << idx++ << ", doc count " << multi_string_attr_mem_indexer.DocCount();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });
    bthread_join(write_bid, nullptr);
    for (auto read_bid : read_bids) {
        bthread_join(read_bid, nullptr);
    }
    stat_thread.join();
}

TEST(single_attribute_test, single_attr_dump) {
    SingleValueAttributeMemIndexer<uint64_t> single_attr_mem_indexer;
    single_attr_mem_indexer.Init(hawking::util::COLUMN_INT64, 0);

    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    SingleValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64);

    uint32_t doc_id = 0;
    std::unordered_map<DocId, DocId> old2new_map;
    while (doc_id < 2048000) {
        hawking::util::FieldValue value;
        value.set_int_value(dis(e));
        std::string_view sv = convertor.Encode(&value, single_attr_mem_indexer.GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(doc_id++);
        single_attr_mem_indexer.AddDocument(doc.get());

        {
            old2new_map.emplace(doc_id, doc_id);
        }
    }

    FslibWrapper::Mkdir("/tmp/single_dump");
    single_attr_mem_indexer.Dump("/tmp/single_dump", old2new_map);
}

TEST(single_attribute_test, string_attr_dump) {
    MultiValueAttributeMemIndexer<char> string_attr_mem_indexer;
    string_attr_mem_indexer.Init(hawking::util::COLUMN_STRING, 0);

    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    StringAttributeConvertor convertor(hawking::util::COLUMN_STRING);

    uint32_t doc_id = 0;
    std::unordered_map<DocId, DocId> old2new_map;
    while (doc_id < 2048000) {
        hawking::util::FieldValue value;
        value.set_bytes_value(std::to_string(dis(e)));
        std::string_view sv = convertor.Encode(&value, string_attr_mem_indexer.GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(doc_id++);
        string_attr_mem_indexer.AddDocument(doc.get());

        {
            old2new_map.emplace(doc_id, doc_id);
        }
    }

    FslibWrapper::Mkdir("/tmp/string_dump");
    string_attr_mem_indexer.Dump("/tmp/string_dump", old2new_map);
}

TEST(multi_attribute_test, multi_value_attr_dump) {
    MultiValueAttributeMemIndexer<int64_t> multi_value_attr_mem_indexer;
    multi_value_attr_mem_indexer.Init(hawking::util::COLUMN_STRING, 0);

    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    MultiValueAttributeConvertor<int64_t> convertor(hawking::util::COLUMN_INT64_LIST);

    uint32_t doc_id = 0;
    std::unordered_map<DocId, DocId> old2new_map;
    while (doc_id < 2048000) {
        hawking::util::FieldValue int64_list;
        int32_t r_count = dis2(e);
        for (int32_t idx = 0; idx < r_count; ++idx) {
            int64_list.mutable_int_values()->add_values(dis(e));
        }
        std::string_view sv = convertor.Encode(&int64_list, multi_value_attr_mem_indexer.GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(doc_id++);
        multi_value_attr_mem_indexer.AddDocument(doc.get());

        {
            old2new_map.emplace(doc_id, doc_id);
        }
    }

    FslibWrapper::Mkdir("/tmp/multi_value_dump");
    multi_value_attr_mem_indexer.Dump("/tmp/multi_value_dump", old2new_map);
}

TEST(multi_attribute_test, multi_string_attr_dump) {
    MultiValueAttributeMemIndexer<char> multi_string_attr_mem_indexer;
    multi_string_attr_mem_indexer.Init(hawking::util::COLUMN_STRING, 0);

    std::unique_ptr<NormalDocument> doc = std::make_unique<NormalDocument>();
    std::shared_ptr<AttributeDocument> attr_doc = std::make_shared<AttributeDocument>();
    attr_doc->Reserve(1);
    doc->SetAttributeDocument(attr_doc);
    doc->SetOperatorType(hawking::util::IndexOp::INDEX_RT_ADD);
    MultiStringAttributeConvertor convertor(hawking::util::COLUMN_STRING_LIST);

    uint32_t doc_id = 0;
    std::unordered_map<DocId, DocId> old2new_map;
    while (doc_id < 2048000) {
        hawking::util::FieldValue bytes_list;
        int32_t r_count = dis2(e);
        for (int32_t idx = 0; idx < r_count; ++idx) {
            bytes_list.mutable_bytes_values()->add_values(std::to_string(dis(e)));
        }
        std::string_view sv = convertor.Encode(&bytes_list, multi_string_attr_mem_indexer.GetPool());

        attr_doc->SetField(0, sv);
        doc->SetDocId(doc_id++);
        multi_string_attr_mem_indexer.AddDocument(doc.get());

        {
            old2new_map.emplace(doc_id, doc_id);
        }
    }

    FslibWrapper::Mkdir("/tmp/multi_string_dump");
    multi_string_attr_mem_indexer.Dump("/tmp/multi_string_dump", old2new_map);
}

int main(int argc, char* argv[]) {
    ::testing::InitGoogleTest(&argc, argv);
    ::google::ParseCommandLineFlags(&argc, &argv, true);
    srand(static_cast<unsigned>(time(0)));
    return RUN_ALL_TESTS();
}
